<!DOCTYPE html>
<head>
  <title>MyVue</title>
</head>
<style>
  #app {
    text-align: center;
  }
</style>
<body>
	<div id="app">
	    aaaa
	</div>
</body>

<script>
 /**
 * Dep是数据和Watcher之间的桥梁，主要实现了以下两个功能：
 * 1.用 addSub 方法可以在目前的 Dep 对象中增加一个 Watcher 的订阅操作；
 * 2.用 notify 方法通知目前 Dep 对象的 subs 中的所有 Watcher 对象触发更新操作。
 */
 class Dep {
    constructor () {
        // 用来存放Watcher对象的数组
        this.subs = [];
    }
    addSub (sub) {
        // 往subs中添加Watcher对象
        this.subs.push(sub);
    }
    // 通知所有Watcher对象更新视图
    notify () {
        this.subs.forEach((sub) => {
            sub.update();
        })
    }
}

// 观察者对象
class Watcher {
    constructor () {
        // Dep.target表示当前全局正在计算的Watcher（当前的Watcher对象），在get中会用到
        Dep.target = this;
    }
    // 更新视图
    update () {
        console.log("视图更新啦");
    }
}

Dep.target = null;

class Vue {
    // Vue构造类
    constructor(options) {
        this._data = options.data;
        this.observer(this._data);
        // 实例化Watcher观察者对象，这时候Dep.target会指向这个Watcher对象
        new Watcher();
        console.log('render', this._data.message);
    }
    // 对Object.defineProperty进行封装，给对象动态添加setter和getter
    defineReactive (obj, key, val) {
        const dep = new Dep();
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: function reactiveGetter ()  {
                // 往dep中添加Dep.target（当前正在进行的Watcher对象）
                console.log('getdatagetdata')
                dep.addSub(Dep.target);
                return val;         
            },
            set: function reactiveSetter (newVal) {
                if (newVal === val) return;
                // 在set的时候通知dep的notify方法来通知所有的Wacther对象更新视图
                dep.notify();
            }
        });
    }
    // 对传进来的对象进行遍历执行defineReactive
    observer (value) {
        console.log('value',value)
        if (!value || (typeof value !== 'object')) {
            return;
        }
        Object.keys(value).forEach((key) => {
            this.defineReactive(value, key, value[key]);
        });
    }
}
let obj = new Vue({
  el: "#app",
  data: {
      message: 'test',
      name: 'xw',
      sex: '1'
  }
})
obj._data.message = 'update'

// console.log('Dep',new Dep())
// console.log('Dep',Dep.target)

obj._data.name = 'zy'
</script>